

package cn.liyao.web.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.liyao.im.util.ConversationUtil;
import cn.liyao.tool.annotation.RequireToken;
import cn.liyao.tool.api.R;
import cn.liyao.web.constant.ConversationType;
import cn.liyao.web.constant.MessageTypeU;
import cn.liyao.web.holder.CurrentUserIdHolder;
import cn.liyao.web.model.*;
import cn.liyao.web.repository.*;
import io.netty.util.internal.StringUtil;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import server.processor.OnlineProcessor;
import server.protocal.Protocal;
import server.protocal.ProtocalFactory;
import server.utils.LocalSendHelper;

import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@RestController
public class GroupController {

    private final GroupRepository groupRepository;

    private final GroupMemberRepository groupMemberRepository;

    private final UserRepository userRepository;

    private final ConversationRepository conversationRepository;

    private final MessageRepository messageRepository;


    private final ConversationUtil conversationUtil;

    private final GroupNoticeRepository groupNoticeRepository;


    public GroupController(GroupRepository groupRepository, GroupMemberRepository groupMemberRepository, UserRepository userRepository, ConversationRepository conversationRepository, MessageRepository messageRepository, ConversationUtil conversationUtil, GroupNoticeRepository groupNoticeRepository) {
        this.groupRepository = groupRepository;
        this.groupMemberRepository = groupMemberRepository;
        this.userRepository = userRepository;
        this.conversationRepository = conversationRepository;
        this.messageRepository = messageRepository;
        this.conversationUtil = conversationUtil;
        this.groupNoticeRepository = groupNoticeRepository;
    }

    private Map handlerUsers(String ids, String currentId){
        String[] userIds = ids.split(",");
        List<String> allUserIds = new ArrayList<>();
        allUserIds.add(currentId);
        Collections.addAll(allUserIds, userIds);

        List<User> users = userRepository.findAllById(allUserIds);

        List<Map> formatUsers =  users.stream().map((item)-> {
            Map map = new HashMap();
            map.put("userId", item.getUserId());
            map.put("nickName", item.getNickName());
            return map ;
        }).collect(Collectors.toList());

        String names =  users.stream().map(item-> item.getUserName()).limit(3).collect(Collectors.joining("、"));
        Optional<User> loginUser =  users.stream().filter(item-> item.getUserId().equals(currentId)).findFirst();
        List<Map> invitations = formatUsers.stream().filter(item-> !item.get("userId").toString().equals(loginUser.get().getUserId())).collect(Collectors.toList());

        return new HashMap(){{
            put("names",names);
            put("loginUser",loginUser.get());
            put("invitations", invitations);
            put("users", users);
            put("allUserIds", allUserIds);
        }};
    }



    private   List<Map>  GetInvitations(List<User> users, String  currentId){
        List<Map> formatUsers =  users.stream().map((item)-> {
            Map map = new HashMap();
            map.put("userId", item.getUserId());
            map.put("nickName", item.getNickName());
            return map ;
        }).collect(Collectors.toList());

        List<Map> invitations = formatUsers.stream().filter(item-> !item.get("userId").toString().equals(currentId)).collect(Collectors.toList());

        return invitations;
    }





    @GetMapping("/group/updateName")
    @RequireToken()
    public R updateName(String targetId, String name ) throws Exception {
        String userId = CurrentUserIdHolder.getCurrentUser();
        if(StringUtil.isNullOrEmpty(name)) return R.fail("群名称不能为空");
        Optional<Group> groupOptional =   groupRepository.findById(targetId);
        if(!groupOptional.isPresent()) return R.fail("群组不存在");
        Group group = groupOptional.get();



        Optional<User> userOptional =   userRepository.findById(userId);
        Map<String,String> user = new HashMap<>();
        user.put("nickName",userOptional.get().getNickName());
        user.put("userId",userOptional.get().getUserId());
        Map<String,Object> result = new HashMap<>();
        result.put("Operator",user);
        result.put("groupId",group.getGroupId());
        result.put("creator_time",System.currentTimeMillis());
        result.put("originalName",group.getGroupName());
        result.put("currentName",name);
        Protocal p = ProtocalFactory.createCommonData(JSONUtil.toJsonStr(result), "0", userId, true, null, MessageTypeU.updateNameGroup.getValue());
        Messages messages = new Messages();
        BeanUtils.copyProperties(p, messages);
        messages.setTo(group.getGroupId());
        messageRepository.save(messages);


        conversationUtil.createMessageStatus(messages);



        // 修改群名保存数据库
        group.setGroupName(name);
        groupRepository.save(group);

        // 查询出来所有群用户 通知他们我改名字了
        List<GroupMember> members = groupMemberRepository.findAllByGroupIdAndUserState(targetId,0);
        for(GroupMember item : members){
            p.setTo(item.getUserId());
            createConversation(group.getGroupId(),item.getUserId(),group,userId);
            if(OnlineProcessor.isOnline(item.getUserId())){
                LocalSendHelper.sendData(p, null);
            }
        }






        return R.data("操作成功");
    }



    @GetMapping("/group/remove")
    @RequireToken()
    @Transactional()
    public R groupMembersremove(String targetId, String ids) throws Exception {
        String userId = CurrentUserIdHolder.getCurrentUser();
        Optional<Group> groupOptional =   groupRepository.findById(targetId);
        if(!groupOptional.isPresent()) return R.fail("群组不存在");
        Group group = groupOptional.get();
        Map map =  handlerUsers(ids,userId);
        User loginUser = (User) map.get("loginUser");
        List<User> users = (List<User>) map.get("users");


        if(!group.getCreator().equals(userId)){
            return R.fail("只有群主才有权限");
        }

        List<User> newUsers  = new ArrayList<>();

        for(User user : users){
            GroupMember groupMember =   groupMemberRepository.findByGroupIdAndUserId(group.getGroupId(),user.getUserId());
            if(groupMember != null){
                if(!groupMember.getUserId().equals(userId)){
                    newUsers.add(user);
                }
            }
        }

        List<Map> invitations =  getRemoveInvitations(newUsers,userId);
        Map dataContent  = getRemoveDataContent(loginUser,invitations);
        Protocal p = ProtocalFactory.createCommonData(JSONUtil.toJsonStr(dataContent), "0", userId, true, null, MessageTypeU.removeUserGroup.getValue());
        Messages messages = new Messages();
        BeanUtils.copyProperties(p, messages);
        messages.setTo(group.getGroupId());
        messageRepository.save(messages);

        conversationUtil.createMessageStatus(messages);


        for(User user : newUsers){
           GroupMember groupMember =  groupMemberRepository.findByGroupIdAndUserId(group.getGroupId(),user.getUserId());
           groupMember.setUserState(1);
           groupMember.setLeaveTime(new Date());
           groupMemberRepository.save(groupMember);

            if(OnlineProcessor.isOnline(user.getUserId()) && !user.getUserId().equals(userId)){
                p.setTo(user.getUserId());
                LocalSendHelper.sendData(p, null);
            }
        }

        for(User user : users){
            if(OnlineProcessor.isOnline(user.getUserId()) && !user.getUserId().equals(userId)){
                p.setTo(user.getUserId());
                LocalSendHelper.sendData(p, null);
            }
        }

        return R.data("移除成功");
    }


    @GetMapping("/group/invitation")
    @RequireToken()
    public R groupMembers(String targetId, String ids) throws Exception {
        String userId = CurrentUserIdHolder.getCurrentUser();
        Optional<Group> groupOptional =   groupRepository.findById(targetId);
        if(!groupOptional.isPresent()) return R.fail("群组不存在");

        Group group = groupOptional.get();

        Map map =  handlerUsers(ids,userId);
        User loginUser = (User) map.get("loginUser");
        List<User> users = (List<User>) map.get("users");

        // 过滤掉已经在群里面的用户


        List<User> newUsers  = new ArrayList<>();

        for(User user : users){
            GroupMember groupMember =   groupMemberRepository.findByGroupIdAndUserId(group.getGroupId(),user.getUserId());
            if(groupMember == null){
                newUsers.add(user);
            }else{
                // 因为之前被移除了，所以要恢复出来
               if( groupMember.getUserState() == 1){
                   newUsers.add(user);
               }
            }
        }

        if(newUsers.size() == 0){
            return R.fail("你邀请的用户全部都在群了");
        }


        List<Map> invitations =  GetInvitations(newUsers,userId);
        Map dataContent  = getInvitationDataContent(loginUser,invitations);
        dataContent.put("groupId", group.getGroupId());
        Protocal p = ProtocalFactory.createCommonData(JSONUtil.toJsonStr(dataContent), "0", userId, true, null, MessageTypeU.invitationGroup.getValue());
        Messages messages = new Messages();
        BeanUtils.copyProperties(p, messages);
        messages.setTo(group.getGroupId());
        messageRepository.save(messages);
        conversationUtil.createMessageStatus(messages);


        // newUser 被邀请人
        for(User user : newUsers){
            GroupMember groupMember = groupMemberRepository.findByGroupIdAndUserId(group.getGroupId(), user.getUserId());
            if(groupMember == null){
                groupMember = new GroupMember();
                groupMember.setJoinTime(new Date());
                groupMember.setId(IdUtil.getSnowflakeNextIdStr());
                groupMember.setGroupId(group.getGroupId());
                groupMember.setUserId(user.getUserId());
                groupMemberRepository.save(groupMember);
            }else{
                groupMember.setUserState(0);
                groupMemberRepository.save(groupMember);
            }

            createConversation(targetId,user.getUserId(),group,userId);
        }



        List<GroupMember> groupMemberLit =  groupMemberRepository.findAllByGroupIdAndUserState(group.getGroupId(),0);

        for(GroupMember groupMember : groupMemberLit){
            if(OnlineProcessor.isOnline(groupMember.getUserId()) && !groupMember.getUserId().equals(userId)){
                p.setTo(groupMember.getUserId());
                LocalSendHelper.sendData(p, null);
            }
        }
        return R.success("邀请成功");
    }



    @GetMapping("/group/members")
    @RequireToken()
    public R groupMembers(String id) {
        // 当前登录的用户
        String userId = CurrentUserIdHolder.getCurrentUser();
        List<GroupMember> groupMemberLit =  groupMemberRepository.findAllByGroupIdAndUserState(id,0);
        List<String> userIds =  groupMemberLit.stream().map(item-> item.getUserId()).collect(Collectors.toList());
        List<User> users = userRepository.findAllById(userIds);
        return R.data(users);
    }


    @GetMapping("/group/info")
    @RequireToken()
    public R groupInfo(String id) {

        String userId = CurrentUserIdHolder.getCurrentUser();

        Optional<Group> groupOptional = groupRepository.findById(id);
        if (!groupOptional.isPresent()) return R.fail("群组不存在");

        Group group = groupOptional.get();

       GroupMember groupMember =  groupMemberRepository.findByGroupIdAndUserId(group.getGroupId(), userId);
       if(groupMember !=null){
           if(groupMember.getRemark() != null){
               group.setRemark(groupMember.getRemark());
           }
       }

       GroupNotice groupNotice =  groupNoticeRepository.findFirstByGroupIdOrderByTimeDesc(group.getGroupId());

       group.setNotice(groupNotice);



        return R.data(group);
    }



    @GetMapping("/findGroupById")
    @RequireToken()
    public R findGroupById(String id) {
        Optional<Group> group = groupRepository.findById(id);
        if (!group.isPresent()) return R.fail("群组不存在");
        return R.data(group.get());
    }




    private List<Map>  getRemoveInvitations(List<User> users, String  currentId){
        List<Map> formatUsers =  users.stream().map((item)-> {
            Map map = new HashMap();
            map.put("userId", item.getUserId());
            map.put("nickName", item.getNickName());
            return map ;
        }).collect(Collectors.toList());

        List<Map> invitations = formatUsers.stream().filter(item-> !item.get("userId").toString().equals(currentId)).collect(Collectors.toList());

        return invitations;
    }



    public Map getRemoveDataContent(User loginUser, List<Map> invitations){
        Map<String,String> user = new HashMap<>();
        user.put("nickName",loginUser.getNickName());
        user.put("userId",loginUser.getUserId());
        Map<String,Object> result = new HashMap<>();
        result.put("Operator",user);
        result.put("creator_time",System.currentTimeMillis());
        result.put("removes",invitations);
        return result;
    }




    public Map getInvitationDataContent(User loginUser, List<Map> invitations){
        Map<String,String> user = new HashMap<>();
        user.put("nickName",loginUser.getNickName());
        user.put("userId",loginUser.getUserId());
        Map<String,Object> result = new HashMap<>();
        result.put("invitation",user);
        result.put("creator_time",System.currentTimeMillis());
        result.put("invitations",invitations);
        return result;
    }




    public Map getCreateDataContent(User loginUser, List<Map> invitations){
        Map<String,String> user = new HashMap<>();
        user.put("nickName",loginUser.getNickName());
        user.put("userId",loginUser.getUserId());
        Map<String,Object> result = new HashMap<>();
        result.put("creator",user);
        result.put("creator_time",System.currentTimeMillis());
        result.put("invitations",invitations);
        return result;
    }




    @SneakyThrows
    @GetMapping("/group/create")
    @RequireToken()
    public R findUserById(String ids) {
        String userId = CurrentUserIdHolder.getCurrentUser();



        Map map =  handlerUsers(ids,userId);
        String names = map.get("names").toString();
        User loginUser = (User) map.get("loginUser");
        List<Map> invitations = (List<Map>) map.get("invitations");
        List<User> users = (List<User>) map.get("users");
        List<String> allUserIds = (List<String>) map.get("allUserIds");



        if(users.size() > 0){

            Group group = new Group();
            group.setGroupId("group_"+IdUtil.getSnowflakeNextIdStr());
            group.setGroupName(names + "的群");
            group.setCreator(userId);
            group.setCreateTime(new Date());
            groupRepository.save(group);
            List<GroupMember> list = new ArrayList<>();
            for(User item : users){
                GroupMember groupMember = new GroupMember();
                groupMember.setGroupId(group.getGroupId());
                groupMember.setId(IdUtil.getSnowflakeNextIdStr());
                groupMember.setUserId(item.getUserId());
                groupMember.setJoinTime(new Date());
                list.add(groupMember);
            }
            groupMemberRepository.saveAll(list);

            Map dataContent =  getCreateDataContent(loginUser,invitations);
            dataContent.put("groupId",group.getGroupId());

            Protocal p = ProtocalFactory.createCommonData(JSONUtil.toJsonStr(dataContent), "0", userId, true, null, MessageTypeU.createGroup.getValue());
            Messages messages = new Messages();
            BeanUtils.copyProperties(p, messages);
            messages.setTo(group.getGroupId());
            messageRepository.save(messages);
            conversationUtil.createMessageStatus(messages);




            for(String userId1 : allUserIds){
                createConversation(group.getGroupId(),userId1 ,group, userId);
                if(OnlineProcessor.isOnline(userId1) && !userId1.equals(userId)){
                    p.setTo(userId1);
                    LocalSendHelper.sendData(p, null);
                }

            }
            return R.data(group);
        }else{
            return R.fail("用户不存在");
        }

    }



    private void createConversation(String targetId, String userId, Group group, String currentId){
        Conversation conversation =  conversationRepository.findOneByUserIdAndTargetId(userId,targetId);
        if(conversation == null){
            conversation = new Conversation();
            conversation.setId(IdUtil.getSnowflakeNextIdStr());
            conversation.setTargetId(targetId);
            conversation.setUserId(userId);
            conversation.setTimestamp(System.currentTimeMillis());
            conversation.setLastMessage("");
            conversation.setDisturb(false);
            conversation.setUnreadCount( currentId.equals(userId) ? 0 : 1);
            conversation.setTop(false);
            conversation.setType(ConversationType.Group.getValue());
            conversation.setUserName(group.getGroupName());
            conversation.setPortrait(group.getPortrait());
        }else{
            conversation.setPortrait(group.getPortrait());
            conversation.setUserName(group.getGroupName());

            if(!conversation.getDisturb()){

                if(userId.equals(currentId)){
                    conversation.setUnreadCount( conversation.getUnreadCount());
                }else{
                    conversation.setUnreadCount( conversation.getUnreadCount() + 1);
                }

            }else{
                conversation.setUnreadCount(0);
            }

        }
        conversationRepository.save(conversation);
    }


}